package cn.jiangjiesheng.bootstrap.fileport.interfaces;

import com.google.common.collect.Maps;
import cn.jiangjiesheng.bootstrap.commons.exception.BizzException;
import cn.jiangjiesheng.bootstrap.fileport.interfaces.model.ExcelPictModel;
import cn.jiangjiesheng.bootstrap.fileport.interfaces.model.TableDataModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.Set;

/**
 * Created by dev@jiangjiesheng.cn on 2021/11/4  <br/>
 * 表格导出构造器
 *
 * @author dev@jiangjiesheng.cn
 */
@Slf4j
public class ExcelTableExporter {

    /**
     * 存储多个sheet的数据
     */
    private Map<String, TableDataModel> tableDataModelMap = Maps.newTreeMap();

    /**
     * 添加一个Sheet
     *
     * @param sheetName
     * @param tableDataModel
     * @return
     */
    public ExcelTableExporter addTableDataModel(String sheetName, TableDataModel tableDataModel) {
        if (this.tableDataModelMap.containsKey(sheetName)) {
            throw new BizzException("sheetname " + sheetName + " exists");
        }
        this.tableDataModelMap.put(sheetName, tableDataModel);
        return this;
    }

    public File build() {
        XSSFWorkbook workbook = new XSSFWorkbook();
        Map<String, ExcelPictModel> picMap = Maps.newTreeMap();
        //Returns an object that handles instantiating concrete classes
        CreationHelper helper = workbook.getCreationHelper();
        //Adds a picture to the workbook
        // 遍历工作簿
        for (String sheetName : tableDataModelMap.keySet()) {
            // 处理数据
            XSSFSheet sheet = workbook.createSheet(sheetName);
            TableDataModel sheetDataModel = this.tableDataModelMap.get(sheetName);
            Set<String> keySet = sheetDataModel.keySet();
            int rowNum = 0;
            for (String key : keySet) {
                Row row = sheet.createRow(rowNum++);
                Object[] objArr = sheetDataModel.get(key);
                int cellNum = 0;
                for (Object obj : objArr) {
                    Cell cell = row.createCell(cellNum++);
                    if (obj instanceof String) {
                        cell.setCellValue((String) obj);
                    } else if (obj instanceof Integer) {
                        cell.setCellValue((Integer) obj);
                    } else if (obj instanceof ExcelPictModel) {
                        // 图片集整理
                        ExcelPictModel excelPictModel = (ExcelPictModel) obj;
                        int pictureIdx = workbook.addPicture(excelPictModel.getBytes(), excelPictModel.getPicType());
//                        excelPictModel.setRow(rowNum);
                        picMap.put(sheetName + "-" + (pictureIdx + 1), excelPictModel);
                    }
                }
            }
            /*
             * 处理图片 https://stackoverflow.com/questions/33712621/how-put-a-image-in-a-cell-of-excel-java/33721090
             * 图片插入cell
             */

            ClientAnchor anchor;
            Drawing drawing;
            for (String pictureIdx : picMap.keySet()) {
                //Create an anchor that is attached to the worksheet
                anchor = helper.createClientAnchor();
                //Creates the top-level drawing patriarch.
                drawing = sheet.createDrawingPatriarch();
                // 图片贴到对应的sheet
                if (!pictureIdx.startsWith(sheetName + "-")) {
                    continue;
                }
                anchor.setCol1(picMap.get(pictureIdx).getCol());
                anchor.setRow1(picMap.get(pictureIdx).getRow());
                Picture pict = drawing.createPicture(anchor, Integer.valueOf(pictureIdx.replace(sheetName + "-", "")) - 1);
                pict.resize(1);
                // 修改行高
                if (Objects.nonNull(sheet.getRow(picMap.get(pictureIdx).getRow()))) {
                    XSSFRow row = sheet.getRow(picMap.get(pictureIdx).getRow());
                    row.setHeightInPoints(Math.min(picMap.get(pictureIdx).getHeight(), 140));
                    log.info("row height: {}, origin: {}", row.getHeight(), picMap.get(pictureIdx).getHeight());
                } else {
                    log.warn("sheet {} ,row {} 为null", sheetName, picMap.get(pictureIdx).getRow());
                }
                // 修改列宽
                OptionalInt maxWeight = picMap.values().stream().mapToInt(ExcelPictModel::getWeight).max();
                int[] picColumns = picMap.values().stream().mapToInt(ExcelPictModel::getCol)
                        .distinct().toArray();
                log.info("max column width:{}", maxWeight.orElse(-1));
                log.info("columns with pic {} ", picColumns);
                if (maxWeight.isPresent()) {
                    for (Integer picColumn : picColumns) {
                        sheet.setColumnWidth(picColumn, Math.min(maxWeight.getAsInt() * 40, 200 * 40));
                    }
                }
            }
            // sheet loop
        }
        File temporaryFile = null;
        try {
            temporaryFile = File.createTempFile("fileport-", ".xlsx");
            OutputStream outputStream = new FileOutputStream(temporaryFile);
            workbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return temporaryFile;
    }

    public File buildFile() {
        return build();
    }
}
